package gossipinator.bt;

import javax.bluetooth.* ;
import javax.microedition.io.*;
import java.io.*;

/**
 *   Un objet de la classe BT joue le role de client et de serveur.
 *   <p>
 *   Pour avoir un client et un serveur en taches de fond, il est necessaire
 *   de creer deux threads (processus léger) qui appellent les methodes de l'objet BT.
 *   Trouvez rapidement sur le net comment faire des threads.
 *   <p>
 *   NE CONFONDEZ PAS LES APPELS  Serveur_... et Client_...
 */
public class BT {
    
    private static final String ragotronServiceName = "Ragotron";
    private static final String ragotronServiceUUID = "bebef0f0b0f01b0f8b0f000e60123345";
    private UUID ragotronUUID = new UUID(ragotronServiceUUID, false);
	
    private LocalDevice local ;
    private DiscoveryAgent da ;
	
    /** Adresse bluetooth du mobile */
    public String address ;
	
    /* Serveur */
    private StreamConnectionNotifier scn ;
    private DataOutputStream serveur_dos ;
    private DataInputStream  serveur_dis ;
    private StreamConnection serveur_sc ;
    private Handshake handserv ;
    private boolean serveur_connected ;
    
    /* Client */
    private DataOutputStream client_dos ;
    private DataInputStream  client_dis ;
    private StreamConnection client_sc ;
    private Handshake handcli ;
    private boolean client_connected ;
	
    /** Client : cherche un serveur dans le voisinage et s'y connecte (appel bloquant)
     *  <p>
     *  Cause une erreur si le client est deja en communication avec un serveur
     *  (communication precedente mal fermee)
     *  
     */
    public void Client_Cherche_Serveur() {
    	String url = null ;
    	while (url == null) {
	    try {
	    try {
		url = da.selectService(ragotronUUID, ServiceRecord.NOAUTHENTICATE_NOENCRYPT,
				       false);
	    } catch (NullPointerException e) {
	    	// Ces abrutis ils font un nullpointerexception sans raison.
	    }
		if (url != null) {
                    System.out.println("Client : service trouve = " + url);
                }
		Thread.sleep(5000) ;
	    } catch (Exception e) {
		System.out.println("Client_Cherche_Serveur : " + e) ;
	    }}
    	
    	try {
    		this.client_sc = (StreamConnection) Connector.open(url) ;
    		this.client_dos = this.client_sc.openDataOutputStream() ;
    		this.client_dis = this.client_sc.openDataInputStream() ;
    		this.handcli = new Handshake("Client", client_dos, client_dis) ;
    	} catch (Exception e) {
		System.out.println("BTClient.run : " + e) ;
	    }
    	
    	handcli.checkGet(800) ;
    	handcli.checkPut(801) ;
		 
    	this.client_connected = true ;
    }


    /** 
     * Ferme la connexion avec le serveur distant
     */
    public void Client_Fermer() {
	if (!client_connected) {
	    throw new Error("Client_Fermer : ce client n'est pas connecte") ;
	}
		
	try {	
	    this.client_dos.close() ;
	    this.client_dis.close() ;
	    this.client_sc.close() ;
	    this.client_connected = false ;
	} catch (Exception e) {
	    System.out.println ("Client_Fermer : exception " + e) ;
	}
	 
	System.out.println("[Client] Communication terminee.") ;
    }

    /**  
     * @return Canal en ecriture pour communiquer avec le serveur distant
     *  <p>
     * Cause une erreur si le client n'est pas connecte.
     */	
    public DataOutputStream Client_Ecriture() {
	if (!client_connected) {
	    throw new Error("Client_Ecriture : ce client n'est pas connecte.") ;
	}
	return this.client_dos ;
    }
	
    /**  
     * @return Canal en lecture pour communiquer avec le serveur distant
     *  <p>
     * Cause une erreur si le client n'est pas connecte
     */	
    public DataInputStream Client_Lecture() {
	if (!client_connected) {
	    throw new Error("Client_Lecture : le client n'est pas connecte.") ;
	}
	return this.client_dis ;
    }
		 	
    /** Serveur : attend qu'un client se connecte (appel bloquant)
     *  <p>
     * Cause une erreur si le serveur est deja en communication avec un client
     * (communication precedente mal fermee)
     * 
     * @return l'identifiant (adresse BlueTooth) du client. 
     */	
    public String Serveur_Attend_Client() {
	if (this.serveur_connected) {
	    throw new Error("Attend_Client : serveur deja connecte.") ;
	}
		
	try {
	    System.out.println("Serveur en attente de client") ;
	    this.serveur_sc = scn.acceptAndOpen();		 
	    RemoteDevice rd = RemoteDevice.getRemoteDevice(serveur_sc);
	    System.out.println("Serveur : un client connecté : " + rd.getFriendlyName(false));
	    this.serveur_dos = serveur_sc.openDataOutputStream() ;
	    this.serveur_dis = serveur_sc.openDataInputStream() ;
	    this.handserv = new Handshake("Serveur", serveur_dos, serveur_dis) ;
	    this.handserv.checkPut(800) ;
	    this.handserv.checkGet(801) ;
	    this.serveur_connected = true ;
	    return rd.getBluetoothAddress() ;
	} catch (Exception e) {
	    System.out.println("BT.Serveur_Attend_Client : exception " + e) ;
	    return "**connexion echouee**";
	}
    }

    /**  
     * @return Canal en ecriture pour communiquer avec le client connecte
     *  <p>
     * Cause une erreur si aucun client n'est connecte.
     */	
    public DataOutputStream Serveur_Ecriture() {
	if (!serveur_connected) {
	    throw new Error("Serveur_Ecriture : aucun client connecte.") ;
	}
	return this.serveur_dos ;
    }
	
    /**  
     * @return Canal en lecture pour communiquer avec le client connecte
     * Cause une erreur si aucun client n'est connecte.
     */	
    public DataInputStream Serveur_Lecture() {
	if (!serveur_connected) {
	    throw new Error("Serveur_Lecture : aucun client connecte.") ;
	}
	return this.serveur_dis ;
    }
	
    /** 
     * Ferme la connexion avec le client connecte
     */
    public void Serveur_Fermer() {
	if (!serveur_connected) {
	    throw new Error("Serveur_Fermer : aucun client connecte") ;
	}
		
	try {	
	    this.serveur_dos.close() ;
	    this.serveur_dis.close() ;
	    this.serveur_sc.close() ;
	    this.serveur_connected = false ;
	} catch (Exception e) {
	    System.out.println ("Serveur_Fermer : exception " + e) ;
	}
	 
	System.out.println("[Serveur] Communication terminee.") ;
	// On se repose un peu
	try {
	    Thread.sleep(1500) ;
	}
	catch (Exception e) {}
    }


    //RemoteDevice rd[] = new RemoteDevice();
    /** Constructeur tout bete : aucun argument a fournir. */
    public BT() {
	try {
	    this.local = LocalDevice.getLocalDevice() ;
	    this.da = local.getDiscoveryAgent() ;
            //RemoteDevice rd[]=da.retrieveDevices(1);
	    this.address = local.getBluetoothAddress() ;
			
	    // Config du serveur
	    String connURL = "btspp://localhost:"+ragotronUUID.toString()+
		";name="+ragotronServiceName;
	    this.scn = (StreamConnectionNotifier) Connector.open(connURL);
	    this.serveur_connected = false ;
			
	    // CLIENT
	    local.setDiscoverable(DiscoveryAgent.GIAC) ;
	    this.client_connected = false ;
	
			
	} catch (Exception e) {
	    System.out.println("BT() : " + e) ;
	}
    }
}

